#include "dish.h"
#include "chef.h"
#include "priority_queue.h"
#include <stdlib.h>
#include <string.h>

struct Chef_t {
	char *name;
	int score;
	PriorityQueue dishes;
};

#define STARTING_SCORE 0

//helper function for Priority Queue of dishes
static PriorityQueueElement copyDish(PriorityQueueElement dish){
	return dishCopy(dish, NULL);
}

//helper function for Priority Queue of dishes
static void freeDish(PriorityQueueElement dish){
	dishDestroy(dish);
}

/**
 * put a result code in a variable
 * @param result Address to put the code in. if NULL, does nothing.
 * @param code The result code to put in *result
 */
static void putResult(ChefResult *result, ChefResult code){
	if (result!=NULL){
		*result=code;
	}
}

Chef chefCreate(const char *name, ChefResult *result){
	if (name==NULL){
		putResult(result,CHEF_INVALID_ARGUMENT);
		return NULL;
	}
	Chef chef=malloc(sizeof(*chef));
	if (chef==NULL){
		putResult(result,CHEF_OUT_OF_MEMORY);
		return NULL;
	}
	chef->name=malloc(strlen(name)+1);
	if (chef->name==NULL){
		putResult(result,CHEF_OUT_OF_MEMORY);
		free(chef);
		return NULL;
	}
	strcpy(chef->name,name);
	chef->dishes=priorityQueueCreate(copyDish,freeDish);
	if (chef->dishes==NULL){
		putResult(result,CHEF_OUT_OF_MEMORY);
		chefDestroy(chef);
		return NULL;
	}
	chef->score=STARTING_SCORE;
	putResult(result,CHEF_SUCCESS);
	return chef;
}

Chef chefCopy(Chef chef, ChefResult *result){
	if (chef==NULL){
		putResult(result,CHEF_INVALID_ARGUMENT);
		return NULL;
	}
	Chef copiedChef=malloc(sizeof(*copiedChef));
	if (copiedChef==NULL){
		putResult(result,CHEF_OUT_OF_MEMORY);
		return NULL;
	}
	copiedChef->name=malloc(strlen(chef->name)+1);
	if (copiedChef->name==NULL){
		putResult(result,CHEF_OUT_OF_MEMORY);
		free(copiedChef);
		return NULL;
	}
	strcpy(copiedChef->name,chef->name);
	copiedChef->dishes=priorityQueueCopy(chef->dishes);
	if(copiedChef->dishes==NULL){
		putResult(result,CHEF_OUT_OF_MEMORY);
		chefDestroy(copiedChef);
		return NULL;
	}
	copiedChef->score=chef->score;
	putResult(result,CHEF_SUCCESS);
	return copiedChef;
}

void chefDestroy(Chef chef){
	if(chef==NULL){
		return;
	}
	free(chef->name);
	priorityQueueDestroy(chef->dishes);
	free(chef);
}

const char *chefGetName(Chef chef){
	if (chef==NULL){
		return NULL;
	}
	return chef->name;
}

int chefGetScore(Chef chef){
	if (chef==NULL){
		return -1;
	}
	return chef->score;
}

void chefIncrementScore(Chef chef){
	if (chef==NULL){
		return;
	}
	(chef->score)++;
}

void chefAddDish(Chef chef, Dish dish, int favorite,
		ChefResult *result){
	if (chef==NULL || dish==NULL || favorite<0){
		putResult(result,CHEF_INVALID_ARGUMENT);
		return;
	}
	PriorityQueueResult queueResult=priorityQueueAdd(
			chef->dishes,dish,favorite);
	if(queueResult==PRIORITY_QUEUE_OUT_OF_MEMORY){
		putResult(result,CHEF_OUT_OF_MEMORY);
		return;
	}
	putResult(result,CHEF_SUCCESS);
}

Dish chefGetFavoriteDish(Chef chef, ChefResult *result){
	if (chef==NULL){
		putResult(result,CHEF_INVALID_ARGUMENT);
		return NULL;
	}
	if(priorityQueueGetSize(chef->dishes)==0){
		putResult(result,CHEF_NO_DISHES);
		return NULL;
	}
	putResult(result,CHEF_SUCCESS);
	return priorityQueueTop(chef->dishes);
}

void chefRemoveFavoriteDish(Chef chef, ChefResult *result){
	if (chef==NULL){
		putResult(result,CHEF_INVALID_ARGUMENT);
		return;
	}
	if(priorityQueuePop(chef->dishes)==PRIORITY_QUEUE_EMPTY){
		putResult(result,CHEF_NO_DISHES);
		return;
	}
	putResult(result,CHEF_SUCCESS);
}
